package com.seanLab.tool.TagSuggestModel;

import com.google.gson.Gson;
import com.seanLab.domain.TagInfo;
import com.seanLab.dto.RecommendArticleDto;
import com.seanLab.dto.SuggestArticleKeywordsDto;
import com.seanLab.dto.SuggestModelArticleDto;
import com.seanLab.dto.SuggestModelImageDto;
import com.seanLab.tool.TagSuggestModel.TopicModel.MyLDAModel;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 关键词标注／提取模型
 * 数据流向：RawInfoExtractor —(文本)—> FeatureExtractor —(关键词)—> ModelKernel
 */
public class TagSuggestModel {
    protected RawInfoExtractor rawInfoExtractor; //从article中提取相应的信息，如标题、内容、上下文
    protected FeatureExtractor featureExtractor; //从提取信息中抽取关键词，利用ExpandRank或TextRank等
    protected ModelKernel modelKernel; //混合各来源关键词，采用平均混合策略或加权平均策略等
    protected static MyLDAModel ldaModel;

    protected RawInfoType[] rawInfoNeed = new RawInfoType[]
            {RawInfoType.TITLE, RawInfoType.CONTENT};
//    protected RawInfoType[] rawInfoNeed = new RawInfoType[]
//            {RawInfoType.CONTENT};
    protected RawInfoType[] rawInfoNeedForImage = new RawInfoType[]
            {RawInfoType.TITLE, RawInfoType.CONTENT, RawInfoType.PARA_ABOVE_IMAGE,
             RawInfoType.PARA_UNDER_IMAGE, RawInfoType.DESC_OF_IMAGE};
//    protected RawInfoType[] rawInfoNeedForImage = new RawInfoType[]
//        {RawInfoType.CONTENT};

    public TagSuggestModel() {
        rawInfoExtractor = new RawInfoExtractorByText();
        featureExtractor = new FeatureExtractorByExpandRank();
        modelKernel = new ModelKernelByWeighted();
    }

    public String trainModel(List<SuggestModelArticleDto> articles) {
        return ((FeatureExtractorByExpandRank)featureExtractor).trainExpandRank(articles);
    }

    public boolean loadModel(String modelPath) {
        try {
            ((FeatureExtractorByExpandRank)featureExtractor).loadExpandRankModel(modelPath);
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public boolean loadLdaModel(String ldaModelPath) {
        if (ldaModel != null) {
            return true;
        }
        try {
            ldaModel = new Gson().fromJson(new BufferedReader(new InputStreamReader(
                            new FileInputStream(ldaModelPath + File.separator + "MyLDAModel.json"))),
                    MyLDAModel.class);
            ldaModel.loadVocabulary(ldaModelPath + File.separator + "vocabulary.dict");
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public List<SuggestArticleKeywordsDto> suggestTagOfArticle(RecommendArticleDto article, int num) {
        article = cleanArticle(article);
        ArrayList<Feature> features = new ArrayList<Feature>();
        for (RawInfoType rawInfoType : rawInfoNeed) {
            RawInfo rawInfo = rawInfoExtractor.extractRawInfo(article,  rawInfoType);
            features.add(featureExtractor.extractFeature(rawInfo, rawInfoType));
        }
        List<TagInfo> tags = modelKernel.suggestTagForArticle(features, rawInfoNeed, num);
        List<SuggestArticleKeywordsDto> keywords = new ArrayList<>();
        for (TagInfo tag : tags) {
            keywords.add(new SuggestArticleKeywordsDto(tag.getTagName(), tag.getTagScore()));
        }
        return keywords;
    }

    public List<SuggestArticleKeywordsDto> suggestTagOfArticleViaTitle(RecommendArticleDto articleDto, int num) {
        articleDto = cleanArticle(articleDto);
        RawInfoType[] rawInfoTypes = new RawInfoType[] {RawInfoType.TITLE, RawInfoType.CONTENT};
        articleDto.setContent("" + articleDto.getTitle() + " " + articleDto.getContent());
        ArrayList<Feature> features = new ArrayList<Feature>();
        for (RawInfoType rawInfoType : rawInfoTypes) {
            RawInfo rawInfo = rawInfoExtractor.extractRawInfo(articleDto,  rawInfoType);
            features.add(featureExtractor.extractFeature(rawInfo, rawInfoType));
        }
        List<TagInfo> tags = modelKernel.suggestTagForArticleFromTitle(features, rawInfoTypes, num);
        List<SuggestArticleKeywordsDto> keywords = new ArrayList<>();
        for (TagInfo tag : tags) {
            keywords.add(new SuggestArticleKeywordsDto(tag.getTagName(), tag.getTagScore()));
        }
        return keywords;
    }

    public List<SuggestArticleKeywordsDto> suggestTagOfArticleViaContent(RecommendArticleDto articleDto, int num) {
        articleDto = cleanArticle(articleDto);
        ArrayList<Feature> features = new ArrayList<>();
        //Fixme: hack title
        String content = "" + articleDto.getTitle() + " " + articleDto.getTitle() + " "
                + " " + articleDto.getTitle() + " " + articleDto.getTitle() + articleDto.getContent();
        RecommendArticleDto article = new RecommendArticleDto(null, content, null);
        RawInfo rawInfo = rawInfoExtractor.extractRawInfo(article, RawInfoType.CONTENT);
        features.add(featureExtractor.extractFeature(rawInfo, RawInfoType.CONTENT));
        List<TagInfo> tags = modelKernel.suggestTagForArticle(features, new RawInfoType[] {RawInfoType.CONTENT}, num);
        List<SuggestArticleKeywordsDto> keywords = new ArrayList<>();
        for (TagInfo tag : tags) {
            keywords.add(new SuggestArticleKeywordsDto(tag.getTagName(), tag.getTagScore()));
        }
        return keywords;
    }

    public List<List<TagInfo>> suggestTagOfImagedArticle(SuggestModelArticleDto article, List<SuggestModelImageDto> imageList, int num) {
        article = cleanArticle(article);
        ArrayList<List<TagInfo>> tagsList = new ArrayList<List<TagInfo>>();
        for (SuggestModelImageDto image : imageList) {
            ArrayList<Feature> features = new ArrayList<Feature>();
            for (RawInfoType rawInfoType : rawInfoNeedForImage) {
                RawInfo rawInfo = rawInfoExtractor.extractRawInfo(article, image, rawInfoType);
                features.add(featureExtractor.extractFeature(rawInfo, rawInfoType));
            }
            tagsList.add(modelKernel.suggestTag(features, rawInfoNeedForImage, num));
        }
        return tagsList;
    }

    public List<Double> suggestTopicDistribution(String content) {
        double[] topics = ldaModel.predictDoc(content);
        List<Double> result = new ArrayList<>();
        for (int i = 0; i < topics.length; i++) {
            result.add(topics[i]);
        }
        return result;
    }

    /**
     * 去除文章中的无关信息
     */
    private RecommendArticleDto cleanArticle(RecommendArticleDto article) {
        RecommendArticleDto cleanArticle = new RecommendArticleDto();
        cleanArticle.setCategory(article.getCategory());
        cleanArticle.setUrl(article.getUrl());
        cleanArticle.setTitle(cleanTitle(article.getTitle()));
        cleanArticle.setContent(cleanContent(article.getContent()));
        return cleanArticle;
    }

    /**
     * 去除文章中的无关信息
     */
    private SuggestModelArticleDto cleanArticle(SuggestModelArticleDto article) {
        SuggestModelArticleDto cleanArticle = new SuggestModelArticleDto();
        cleanArticle.setSuggestModelImageDtoList(article.getSuggestModelImageDtoList());
        cleanArticle.setTags(article.getTags());
        cleanArticle.setTitle(cleanTitle(article.getTitle()));
        cleanArticle.setContent(cleanContent(article.getContent()));
        return cleanArticle;
    }

    private String cleanTitle(String title) {
        title = removeChannel(title);
        return title;
    }

    private String cleanContent(String content) {
        content = removeChannel(content);
        content = removeStatement(content);
        return content;
    }

    /**
     * 去除频道信息
     */
    private String removeChannel(String str) {
        str = str.replaceAll("财经头条","");
        str = str.replaceAll("新浪看点","");
        str = str.replaceAll("牛吧云播财经","");
        str = str.replaceAll("深港通策略","");
        str = str.replaceAll("牛吧云播证券要闻","");
        return str;
    }

    private static final String regexBegin = "^\\s*.{1,25}?[讯|电]\\s*([\\(（].{0,12}?记者.{0,12}?[\\)）])?";
    private static final String regexEnd = "[\\(（]特别声明.{5,100}?[\\)）]\\s*$";
    private static final Pattern patternBegin = Pattern.compile(regexBegin, Pattern.MULTILINE | Pattern.UNICODE_CHARACTER_CLASS);
    private static final Pattern patternEnd = Pattern.compile(regexEnd, Pattern.MULTILINE | Pattern.UNICODE_CHARACTER_CLASS);

    /**
     * 去除通稿信息
     */
    private String removeStatement(String str) {
        Matcher matcher = patternBegin.matcher(str);

        if (matcher.find()) {
//            System.out.println("Full match: " + matcher.group(0));
            str =  matcher.replaceFirst("");
        }

        matcher = patternEnd.matcher(str);
        if (matcher.find()) {
            str = matcher.replaceAll("");
        }
        return str;
    }

    private static class TestClean {
        public static void main(String[] args) {
            String testContent = "红网时刻10月11日讯（记者 喻向阳）停牌近半年的加加食品今晚发布公告称，公司股票拟定10月12日复牌。公司当日亦召开关于终止重组的投资者说明会，就终止收购辣妹子食品股份有限公司（下称“辣妹子”）一事向投资者问询作出逐一答复，并释疑了上市公司股权质押的相关问题，“并无忧虑”。加加食品强调，今后将持续做大做强调味品产业链。诉求不一协商未成回查公告，加加食品于4月20日起停牌，5月初转入重大资产重组程序并继续停牌，拟购买的标的资产为辣妹子100%股权。披露显示，辣妹子成立于1998年，主要经营罐头、豆制品、蔬菜制品（酱腌菜）、调味料等。辣妹子与加加食品主业存在较大的关联性。就此，加加食品聘请相关中介机构对标的进行了历时数月的尽职调查，并与交易各方进行了多次磋商谈判。工商登记显示，辣妹子股东众多，涉及多方法人主体及自然人小股东，利益诉求存在较大不同，这给协商带来了较大的不确定性。具体来看，石河子东兴博大股权投资合伙企业（有限合伙）控股辣妹子55%股份，湖南友谊阿波罗控股股份有限公司、远大科技集团则分别持股15.2497%、14.518%，余下六位自然人股东分别持0.119%—7.259%不等的股份。据公告披露，公司与有关各方积极推进本次重大资产重组的各项工作，但由于重组相关各方利益诉求不尽相同，公司与交易对方无法就交易事项部分核心条款达成一致。基于此，决定终止筹划本次重大资产重组事项。聚焦调味品产业链不过，加加食品同时制定了“进可攻退可守”的候补方案，着眼于未来对相关潜在标的进行培育及规范化治理。加加食品10月10日与朴和基金签署协议，拟合作发起设立食品行业并购基金，主要用于投资辣妹子及其他具有良好收益前景的食品行业标的资产。停牌期间，食品、调味品行业上市公司股价获得较大涨幅。以海天味业为例，其由今年4月下旬的35元/股左右上涨到目前的48.73元/股，累计涨幅接近四成。也有部分投资者担心，加加食品可能存在复牌后股价下跌风险，及大股东持股质押率较高的问题。对此，加加食品方面表示，大股东方面此前通过股份质押融资进行了一些实业投资，已获得较好资金回报，“手中有足够现金。此外，质押预警线相对较低，股价下跌带来的风险不大。”在回答投资者提问中，加加食品透露，将继续围绕调味品产业链寻求产业投资、并购和整合等外延式增长的机会，加强产融结合。（特别声明：以上文章内容仅代表作者本人观点，不代表新浪看点观点或立场。如有关于作品内容、版权或其它问题请于作品发布后的30日内与新浪看点联系。）";
            System.out.println(new TagSuggestModel().removeStatement(testContent));
        }
    }
}
